#include "ET++.ph"
#include "Converter.h"

#include "Class.h"
#include "Data.h"
#include "Bitmap.h"
#include "String.h"
#include "Ink.h"
#include "TypeMatcher.h"
#include "ET_stdio.h"

static const Symbol cDocTypeXPM("XPM");

//---- XPMMatcher --------------------------------------------------------------

class XPMMatcher: public TypeMatcher {
public:
	XPMMatcher() : TypeMatcher(cDocTypeXPM, "xpm", 0, TRUE)
		{ }
	bool MatchContents(Data*, const char *b, int len);
	Bitmap *GetBitmap()
		{ return gImageIcon; }
};

bool XPMMatcher::MatchContents(Data*, const char *b, int)
{
	if (strncmp(b, "! XPM", 5) == 0)
		return TRUE;
	if (strncmp(b, "/* XPM */", 9) == 0)
		return TRUE;
	return FALSE;
}

static XPMMatcher xpmmatcher;

//---- XPMConverter ------------------------------------------------------------

class XPMConverter : public Converter {
public:
	MetaDef(XPMConverter);
	XPMConverter()
		{ }
	const char *AsString()
		{ return "XPM"; }
	Object *Convert(Data *data, Class *want);
	bool CanConvert(Data *data, Class *want)
		{ return data->Type() == cDocTypeXPM && want == Meta(Bitmap); }
	bool CanConvertTo(Object *op)
		{ return op->IsKindOf(Bitmap); }
	bool ConvertTo(Data *data, Object *op);

private:
	int Getchar();
	int getline(char **b);

private:
	FILE *ifp;
	int line, eof, inside;
};

NewMetaImpl0(XPMConverter,Converter);

int XPMConverter::getline(char **b)
{
	static char buf[2048];
	int c;
	register char *cp= buf;
		
	for (;;) {
		c= Getchar();
		if (c == '\n' || c == EOF) {
			*cp= 0;
			*b= buf;
			return cp-buf;
		}
		*cp++= c;
	}
}

int XPMConverter::Getchar()
{
	int c;

restart:
	if (eof)
		return EOF;
	c= fgetc(ifp);
	if (c == EOF) {
		eof= 1;
		return c;
	}
	if (c == '"') {
		inside= !inside;
		if (!inside)
			return '\n';
		goto restart;
	}
	if (!inside)
		goto restart;
	return c;
}

Object *XPMConverter::Convert(Data *data, Class*)
{
	char *msg= 0;
	Object *bm= 0;
	FILE *fp= fopen(data->Name(), "r");
	if (fp) {
		int i= 0;
		char buf[1000], *lines[200];

		fgets(buf, 1000, fp);
		if (strncmp(buf, "/* XPM */", 9) == 0) {
			char *bp;

			ifp= fp;
			eof= inside= 0;
			while (getline(&bp))
				lines[i++]= strsave(bp);
		} else if (strncmp(buf, "! XPM", 5) == 0) {
			while (fgets(buf, 1000, fp)) {
				for (char *cp= buf; *cp; cp++)
					if (*cp == '\n')
						*cp= 0;
				lines[i++]= strsave(buf);
			}
		}
		lines[i]= 0;
		
		bm= new Bitmap((const char**)lines);
		
		for (i= 0; lines[i]; i++)
			delete lines[i];

		fclose(fp);
	} else
		msg= "can't open file\n";
	if (msg)
		fprintf(stderr, "XPMConverter::Convert: %s\n", msg);
	return bm;
}

bool XPMConverter::ConvertTo(Data *data, Object *op)
{
	int x, y;
	Bitmap *bm= (Bitmap*) op;
	Point e(bm->Size());
	FILE *ofp;
	RGB c;
	char *cp, name[100];

	if ((ofp= fopen((char*) data->Name(), "w")) == 0)
		return FALSE;
		
	strcpy(name, data->ShortName());
	if (cp= strchr(name, '.'))
		*cp= 0;

	int s= (int) bm->MaxPixelValue()+1;

	fprintf(ofp, "/* XPM */\n");
	fprintf(ofp, "static char *%s[] = {\n", name);
	fprintf(ofp, "/* %s pixmap\n", name);
	fprintf(ofp, " * width height ncolors chars_per_pixel */\n");
	fprintf(ofp, "\"%d %d %d 1\",\n", e.x, e.y, s);

	for (x= 0; x < s; x++) {
		fprintf(ofp, "\"%c c ", x+'0');
		bm->PixelToRGB(x, &c);
		char *nm= gInkManager->FindName(c, TRUE);
		if (nm)
			fprintf(ofp, "%s\",\n", nm);
		else
			fprintf(ofp, "#%02x%02x%02x\",\n", c.red, c.green, c.blue);
	}

	fprintf(ofp, "/* pixels */\n");
	for (y= 0; y < e.y; y++) {
		fprintf(ofp, "\"");
		for (x= 0; x < e.x; x++)
			fputc((char)(bm->GetPixel(x, y)+'0'), ofp);
		fprintf(ofp, "\",\n");
	}
	fprintf(ofp, "0\n");
	fprintf(ofp, "} ;\n\n");

	fclose(ofp);
	return FALSE;
}

